package com.quiz.bis.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.github.yulichang.wrapper.UpdateJoinWrapper;
import com.quiz.bis.domain.bo.ExamGroupApplyBo;
import com.quiz.bis.domain.bo.ExamGroupBo;
import com.quiz.bis.domain.vo.ExamGroupApplicationVo;
import com.quiz.common.core.domain.R;
import com.quiz.common.core.domain.entity.SysUser;
import com.quiz.common.exception.ServiceException;
import com.quiz.common.mybatis.core.page.PageQuery;
import com.quiz.common.mybatis.core.page.TableDataInfo;
import com.quiz.bis.domain.bo.ExamGroupQueryBo;
import com.quiz.bis.domain.model.*;
import com.quiz.bis.domain.vo.ExamGroupVo;
import com.quiz.bis.mapper.*;
import com.quiz.bis.service.IExamGroupService;
import com.quiz.common.mybatis.core.query.LambdaQueryWrapperPlus;
import com.quiz.common.mybatis.core.query.PlusWrappers;
import com.quiz.common.utils.SecurityUtils;
import com.quiz.system.mapper.SysUserMapper;
import com.sun.org.apache.xpath.internal.operations.Plus;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 考试组服务实现
 *
 * @author ahuan
 */
@Service
@RequiredArgsConstructor
public class ExamGroupServiceImpl implements IExamGroupService {
    private final ExamGroupMapper examGroupMapper;
    private final ExamGroupMemberMapper memberMapper;
    private final ExamGroupInviteMapper inviteMapper;
    private final ExamGroupInviteRecordMapper inviteRecordMapper;
    private final SysUserMapper userMapper;

    @Override
    public TableDataInfo<ExamGroupVo> queryMainOwnerGroups(ExamGroupQueryBo queryBo, PageQuery pageQuery) {
        Page<ExamGroup> examGroupPage = examGroupMapper.selectMainOwnerGroups(
                pageQuery.build(),
                queryBo.getUserId()
        );
        List<ExamGroupVo> examGroupVos = BeanUtil.copyToList(examGroupPage.getRecords(), ExamGroupVo.class);
        return new TableDataInfo<>(examGroupVos, examGroupPage.getTotal());
    }

    @Override
    public TableDataInfo<ExamGroupVo> querySecondaryOwnerGroups(ExamGroupQueryBo queryBo, PageQuery pageQuery) {
        Page<ExamGroup> page = examGroupMapper.selectSecondaryOwnerGroups(
                new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()),
                queryBo.getUserId()
        );
        List<ExamGroupVo> examGroupVos = BeanUtil.copyToList(page.getRecords(), ExamGroupVo.class);
        return new TableDataInfo<>(examGroupVos, page.getTotal());
    }

    @Override
    public TableDataInfo<ExamGroupVo> queryMemberGroups(ExamGroupQueryBo queryBo, PageQuery pageQuery) {
        Page<ExamGroup> page = examGroupMapper.selectMemberGroups(
                new Page<>(queryBo.getPageNum(), queryBo.getPageSize()),
                queryBo.getUserId()
        );

        List<ExamGroupVo> examGroupVos = BeanUtil.copyToList(page.getRecords(), ExamGroupVo.class);
        return new TableDataInfo<>(examGroupVos, page.getTotal());
    }

    @Override
    public TableDataInfo<ExamGroupVo> queryDisabledOrQuitGroups(ExamGroupQueryBo queryBo, PageQuery pageQuery) {
        Page<ExamGroup> page = examGroupMapper.selectDisabledOrQuitGroups(
                new Page<>(queryBo.getPageNum(), queryBo.getPageSize()),
                queryBo.getUserId()
        );
        List<ExamGroupVo> examGroupVos = BeanUtil.copyToList(page.getRecords(), ExamGroupVo.class);
        return new TableDataInfo<>(examGroupVos, page.getTotal());
    }

    @Override
    public TableDataInfo<ExamGroupVo> queryPendingInvites(ExamGroupQueryBo queryBo, PageQuery pageQuery) {
        LambdaQueryWrapper<ExamGroupInviteRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ExamGroupInviteRecord::getInviteeId, queryBo.getUserId())
                .eq(ExamGroupInviteRecord::getStatus, 0)
                .eq(ExamGroupInviteRecord::getDelFlag, 0)
                .eq(ExamGroupInviteRecord::getInviteType, 2);//主动邀请

        Page<ExamGroupInviteRecord> page = inviteRecordMapper.selectPage(
                new Page<>(queryBo.getPageNum(), queryBo.getPageSize()),
                wrapper
        );

        List<Long> groupIds = page.getRecords().stream()
                .map(ExamGroupInviteRecord::getExamGroupId)
                .collect(Collectors.toList());

        if (groupIds.isEmpty()) {
            return TableDataInfo.build();
        }

        List<ExamGroupVo> groups = examGroupMapper.selectVoList(
                new LambdaQueryWrapper<ExamGroup>()
                        .in(ExamGroup::getId, groupIds)
        ).stream().map(group -> {
            ExamGroupVo vo = new ExamGroupVo();
            // 基础字段转换
            vo.setId(group.getId());
            vo.setName(group.getName());
            vo.setCoverImage(group.getCoverImage());
            vo.setMainOwnerId(group.getMainOwnerId());
            vo.setOriginalOwnerId(group.getOriginalOwnerId());
            vo.setDescription(group.getDescription());
            vo.setMaxSubgroups(group.getMaxSubgroups());
            vo.setStatus(group.getStatus());
            vo.setCreateBy(group.getCreateBy());
            vo.setCreateTime(group.getCreateTime());
            vo.setUpdateBy(group.getUpdateBy());
            vo.setUpdateTime(group.getUpdateTime());
            vo.setDelFlag(group.getDelFlag());
            vo.setDeptId(group.getDeptId());

            // 关联字段转换
            vo.setMainOwnerName(group.getMainOwnerName());
            vo.setMemberCount(group.getMemberCount());

            return vo;
        }).collect(Collectors.toList());

        // 补充邀请信息
        page.getRecords().forEach(invite -> {
            groups.stream()
                    .filter(g -> Objects.equals(g.getId(), invite.getExamGroupId()))
                    .findFirst()
                    .ifPresent(vo -> {
                        vo.setInviteId(invite.getId());
                        vo.setInviteCode(invite.getInviteCode());
                        vo.setInviteType(invite.getInviteType());
                        vo.setInviterId(invite.getInviterId());
                        vo.setInviterName(invite.getInviterId().toString());
                        // 设置邀请人姓名
                    });
        });

        return new TableDataInfo<>(groups, page.getTotal());
    }

    @Override
    @Transactional
    public R<Void> applyJoinGroup(ExamGroupApplyBo applyBo) {
        // 验证邀请码
        ExamGroupInvite invite = inviteMapper.selectValidInvite(
                applyBo.getGroupId(),
                applyBo.getInviteCode()
        );
        if (invite == null) {
            throw new ServiceException("邀请码无效或已过期");
        }
        MPJLambdaWrapper<ExamGroupMember> wrapper = new MPJLambdaWrapper<>(ExamGroupMember.class)
                .eq(ExamGroupMember::getExamGroupId, applyBo.getGroupId())
                .eq(ExamGroupMember::getUserId, applyBo.getUserId())
                .disableLogicDel();
        // 检查是否已加入（del_flag=2取消审核、status=3退出考试组，status=4拒绝进入考试组，否则都视为已加入考试组）
        ExamGroupMember examGroupMember = memberMapper.selectJoinOne(ExamGroupMember.class, wrapper);
        if (null != examGroupMember && examGroupMember.getDelFlag() == 0
                && examGroupMember.getApproveStatus() != 2
                && examGroupMember.getApproveStatus() != 3) {
            throw new ServiceException("您已申请加入该考试组");
        }

        // 创建成员记录
        ExamGroupMember member = new ExamGroupMember();
        member.setExamGroupId(applyBo.getGroupId());
        member.setUserId(applyBo.getUserId());
        member.setRole(2); // 次要负责人
        member.setApproveStatus(0); // 负责人邀请码直接通过
        member.setJoinSource(1); // 邀请码加入
        member.setCreateBy(applyBo.getUserId().toString());
        member.setCreateTime(new Date());
        member.setDeptId(SecurityUtils.getDeptId());

        // 更新邀请码使用次数
        if (invite.getMaxUses() != null && invite.getMaxUses() > 0) {
            inviteMapper.updateUsedCount(invite.getId());
        }

        // 生成申请记录
        ExamGroupInviteRecord record = new ExamGroupInviteRecord();
        record.setExamGroupId(applyBo.getGroupId());
        record.setStatus(0);
        record.setInviteType(1);
        record.setInviteCode(invite.getCode());
        record.setInviteeId(applyBo.getUserId());
        record.setInviterId(Long.parseLong(invite.getCreateBy()));
        inviteRecordMapper.insert(record);

        if (null != examGroupMember && examGroupMember.getDelFlag() == 2) {
            member.setId(examGroupMember.getId());
            member.setDelFlag(0);
            UpdateJoinWrapper<ExamGroupMember> eq = new UpdateJoinWrapper<>(ExamGroupMember.class)
                    .eq(ExamGroupMember::getId, examGroupMember.getId())
                    .set(ExamGroupMember::getDelFlag, 0)
                    .set(ExamGroupMember::getUpdateBy, SecurityUtils.getUserId())
                    .set(ExamGroupMember::getUpdateTime, new Date())
                    .disableLogicDel();
            memberMapper.updateJoin(member, eq);
            return R.ok(null, "申请成功");
        }

        if (null != examGroupMember
                && (examGroupMember.getApproveStatus() == 2 || examGroupMember.getApproveStatus() == 3)) {
            member.setId(examGroupMember.getId());
            UpdateJoinWrapper<ExamGroupMember> eq = new UpdateJoinWrapper<>(ExamGroupMember.class)
                    .eq(ExamGroupMember::getId, examGroupMember.getId())
                    .set(ExamGroupMember::getApproveStatus, 0)
                    .set(ExamGroupMember::getUpdateBy, SecurityUtils.getUserId())
                    .set(ExamGroupMember::getUpdateTime, new Date());
            memberMapper.updateJoin(member, eq);
            return R.ok(null, "申请成功");
        }

        memberMapper.insert(member);
        return R.ok(null, "申请成功");
    }

    @Override
    @Transactional
    public R<Void> handleInvite(Long inviteId, boolean accept) {
        ExamGroupInviteRecord invite = inviteRecordMapper.selectById(inviteId);
        if (invite == null || invite.getDelFlag() == 1) {
            return R.fail("邀请记录不存在");
        }

        if (invite.getStatus() != 0) {
            return R.fail("该邀请已处理");
        }

        // 更新邀请状态
        invite.setStatus(accept ? 1 : 2);
        invite.setUpdateTime(new Date());
        inviteRecordMapper.updateById(invite);

        if (accept) {
            // 检查是否已加入
            boolean exists = memberMapper.exists(
                    new LambdaQueryWrapper<ExamGroupMember>()
                            .eq(ExamGroupMember::getExamGroupId, invite.getExamGroupId())
                            .eq(ExamGroupMember::getUserId, invite.getInviteeId())
                            .eq(ExamGroupMember::getDelFlag, 0)
            );

            if (!exists) {
                ExamGroupMember member = new ExamGroupMember();
                member.setExamGroupId(invite.getExamGroupId());
                member.setUserId(invite.getInviteeId());
                member.setRole(invite.getInviteType() == 1 ? 2 : 3);
                member.setApproveStatus(1);
                member.setJoinSource(1);
                member.setCreateBy(String.valueOf(getUserId()));
                memberMapper.insert(member);
            }
        }

        return R.ok(null, accept ? "已接受邀请" : "已拒绝邀请");
    }

    @Override
    @Transactional
    public R<Void> transferOwnership(Long groupId, Long newOwnerId) {
        // 1. 验证当前用户是否是主要负责人
        Long userId = getUserId();
        ExamGroup group = examGroupMapper.selectById(groupId);
        if (group == null || group.getDelFlag() == 1) {
            return R.fail("考试组不存在");
        }

        if (!Objects.equals(group.getMainOwnerId(), userId)) {
            return R.fail("只有主要负责人可以移交权限");
        }

        // 2. 验证新负责人是否是次要负责人
        ExamGroupMember newOwner = memberMapper.selectOne(
                new LambdaQueryWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, newOwnerId)
                        .eq(ExamGroupMember::getRole, 2)
                        .eq(ExamGroupMember::getDelFlag, 0)
        );

        if (newOwner == null) {
            return R.fail("只能移交给次要负责人");
        }

        // 3. 更新考试组主要负责人
        group.setMainOwnerId(newOwnerId);
        examGroupMapper.updateById(group);

        // 4. 更新成员角色
        // 原主要负责人变为次要负责人
        memberMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, userId)
                        .set(ExamGroupMember::getRole, 2)
        );

        // 新次要负责人变为主负责人
        memberMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, newOwnerId)
                        .set(ExamGroupMember::getRole, 1)
        );

        return R.ok(null, "移交成功");
    }

    @Override
    @Transactional
    public R<Void> quitGroup(Long groupId) {
        Long userId = getUserId();

        // 检查是否是主要负责人
        ExamGroup group = examGroupMapper.selectById(groupId);
        if (group != null && Objects.equals(group.getMainOwnerId(), userId)) {
            throw new ServiceException("主要负责人不能直接退出，请先移交权限");
        }

        // 逻辑删除成员记录
        memberMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, userId)
                        .set(ExamGroupMember::getApproveStatus, 3)
                        .set(ExamGroupMember::getUpdateTime, new Date())
                        .set(ExamGroupMember::getUpdateBy, String.valueOf(userId))
        );

        inviteRecordMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupInviteRecord>()
                        .eq(ExamGroupInviteRecord::getExamGroupId, groupId)
                        .eq(ExamGroupInviteRecord::getInviteeId, userId)
                        .set(ExamGroupInviteRecord::getStatus, 3)
                        .set(ExamGroupInviteRecord::getUpdateTime, new Date())
                        .set(ExamGroupInviteRecord::getUpdateBy, String.valueOf(userId))
        );

        return R.ok(null, "退出成功");
    }

    @Override
    public R<Void> enableGroup(Long groupId, boolean enable) {
        Long userId = getUserId();

        // 检查是否是主要负责人
        ExamGroup group = examGroupMapper.selectById(groupId);
        if (group == null || group.getDelFlag() == 1) {
            return R.fail("考试组不存在");
        }

        if (!Objects.equals(group.getMainOwnerId(), userId)) {
            return R.fail("只有主要负责人可以操作");
        }

        group.setStatus(enable ? 1 : 0);
        group.setUpdateBy(String.valueOf(userId));
        group.setUpdateTime(new Date());
        examGroupMapper.updateById(group);

        return R.ok(null, enable ? "启用成功" : "禁用成功");
    }

    @Override
    @Transactional
    public R<Void> deleteGroup(Long groupId) {
        Long userId = getUserId();

        // 检查是否是主要负责人
        ExamGroup group = examGroupMapper.selectById(groupId);
        if (group == null || group.getDelFlag() == 1) {
            return R.fail("考试组不存在");
        }

        if (!Objects.equals(group.getMainOwnerId(), userId)) {
            return R.fail("只有主要负责人可以删除");
        }

        // 检查是否有关联数据
        Long memberCount = memberMapper.selectCount(
                new LambdaQueryWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getDelFlag, 0)
        );

        if (memberCount > 1) { // 大于1是因为还有自己
            return R.fail("考试组中还有成员，无法删除");
        }

        // 逻辑删除考试组
        group.setDelFlag(1);
        group.setUpdateBy(String.valueOf(userId));
        group.setUpdateTime(new Date());
        examGroupMapper.updateById(group);

        // 逻辑删除所有成员关系
        memberMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .set(ExamGroupMember::getDelFlag, 1)
                        .set(ExamGroupMember::getUpdateTime, new Date())
                        .set(ExamGroupMember::getUpdateBy, String.valueOf(userId))
        );

        return R.ok(null, "删除成功");
    }


    // 添加方法实现
    @Override
    @Transactional
    public R<Long> addExamGroup(ExamGroupBo bo) {
        Long userId = getUserId();

        ExamGroup group = new ExamGroup();
        group.setName(bo.getName());
        group.setCoverImage(bo.getCoverImage());
        group.setDescription(bo.getDescription());
        group.setMaxSubgroups(bo.getMaxSubgroups());
        group.setMainOwnerId(userId);
        group.setOriginalOwnerId(userId);
        group.setStatus(1); // 默认启用
        group.setCreateBy(String.valueOf(userId));

        examGroupMapper.insert(group);

        // 添加创建人到成员表
        ExamGroupMember member = new ExamGroupMember();
        member.setExamGroupId(group.getId());
        member.setUserId(userId);
        member.setRole(1); // 主要负责人
        member.setApproveStatus(1); // 自动通过
        member.setJoinSource(0); // 系统创建
        member.setCreateBy(String.valueOf(userId));
        memberMapper.insert(member);

        return R.ok(group.getId());
    }

    @Override
    @Transactional
    public R<Void> updateExamGroup(ExamGroupBo bo) {
        Long userId = getUserId();
        ExamGroup group = examGroupMapper.selectById(bo.getId());

        if (group == null || group.getDelFlag() == 1) {
            return R.fail("考试组不存在");
        }

        // 检查是否是主要负责人
        if (!Objects.equals(group.getMainOwnerId(), userId)) {
            return R.fail("只有主要负责人可以修改");
        }

        group.setName(bo.getName());
        group.setCoverImage(bo.getCoverImage());
        group.setDescription(bo.getDescription());
        group.setMaxSubgroups(bo.getMaxSubgroups());
        group.setUpdateBy(String.valueOf(userId));
        group.setUpdateTime(new Date());

        examGroupMapper.updateById(group);
        return R.ok(null, "修改成功");
    }


    @Override
    public TableDataInfo<ExamGroupVo> queryMemberGroupsOfStudent(ExamGroupQueryBo queryBo, PageQuery pageQuery) {
        IPage<ExamGroupVo> page = examGroupMapper.selectStudentGroups(
                pageQuery.build(),
                queryBo
        );
        return TableDataInfo.build(page);
    }

    @Override
    public ExamGroupVo searchGroupByCode(String code) {
        ExamGroupVo group = examGroupMapper.selectGroupByInviteCode(code);
        if (group == null) {
            throw new ServiceException("邀请码无效或已过期");
        }
        return group;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int studentJoinGroup(ExamGroupApplyBo applyBo) {
        // 验证邀请码
        ExamGroupInvite invite = inviteMapper.selectValidInvite(
                applyBo.getGroupId(),
                applyBo.getInviteCode()
        );
        if (invite == null) {
            throw new ServiceException("邀请码无效或已过期");
        }
        MPJLambdaWrapper<ExamGroupMember> wrapper = new MPJLambdaWrapper<>(ExamGroupMember.class)
                .eq(ExamGroupMember::getExamGroupId, applyBo.getGroupId())
                .eq(ExamGroupMember::getUserId, applyBo.getUserId())
                .disableLogicDel();
        // 检查是否已加入（del_flag=2取消审核、status=3退出考试组，status=4拒绝进入考试组，否则都视为已加入考试组）
        ExamGroupMember examGroupMember = memberMapper.selectJoinOne(ExamGroupMember.class, wrapper);
        if (null != examGroupMember && examGroupMember.getDelFlag() == 0
                && examGroupMember.getApproveStatus() != 2
                && examGroupMember.getApproveStatus() != 3) {
            throw new ServiceException("您已申请加入该考试组");
        }

        // 创建成员记录
        ExamGroupMember member = new ExamGroupMember();
        member.setExamGroupId(applyBo.getGroupId());
        member.setUserId(applyBo.getUserId());
        member.setRole(3); // 考生角色
        member.setApproveStatus(invite.getType() == 1 ? 1 : 0); // 负责人邀请码直接通过
        member.setJoinSource(1); // 邀请码加入
        member.setCreateBy(applyBo.getUserId().toString());
        member.setCreateTime(new Date());
        member.setDeptId(SecurityUtils.getDeptId());

        // 更新邀请码使用次数
        if (invite.getMaxUses() != null && invite.getMaxUses() > 0) {
            inviteMapper.updateUsedCount(invite.getId());
        }

        // 生成申请记录
        ExamGroupInviteRecord record = new ExamGroupInviteRecord();
        record.setExamGroupId(applyBo.getGroupId());
        record.setStatus(0);
        record.setInviteType(1);
        record.setInviteCode(invite.getCode());
        record.setInviteeId(applyBo.getUserId());
        record.setInviterId(Long.parseLong(invite.getCreateBy()));
        inviteRecordMapper.insert(record);

        if (null != examGroupMember && examGroupMember.getDelFlag() == 2) {
            member.setId(examGroupMember.getId());
            member.setDelFlag(0);
            UpdateJoinWrapper<ExamGroupMember> eq = new UpdateJoinWrapper<>(ExamGroupMember.class)
                    .eq(ExamGroupMember::getId, examGroupMember.getId())
                    .set(ExamGroupMember::getDelFlag, 0)
                    .set(ExamGroupMember::getUpdateBy, SecurityUtils.getUserId())
                    .set(ExamGroupMember::getUpdateTime, new Date())
                    .disableLogicDel();
            return memberMapper.updateJoin(member, eq);
        }

        if (null != examGroupMember
                && (examGroupMember.getApproveStatus() == 2 || examGroupMember.getApproveStatus() == 3)) {
            member.setId(examGroupMember.getId());
            UpdateJoinWrapper<ExamGroupMember> eq = new UpdateJoinWrapper<>(ExamGroupMember.class)
                    .eq(ExamGroupMember::getId, examGroupMember.getId())
                    .set(ExamGroupMember::getApproveStatus, 0)
                    .set(ExamGroupMember::getUpdateBy, SecurityUtils.getUserId())
                    .set(ExamGroupMember::getUpdateTime, new Date());
            return memberMapper.updateJoin(member, eq);
        }

        return memberMapper.insert(member);
    }

    @Override
    @Transactional
    public R<Void> quitGroupOfStudent(Long groupId) {
        Long userId = getUserId();

        // 检查是否是成员
        ExamGroupMember member = memberMapper.selectOne(
                new LambdaQueryWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, userId)
                        .eq(ExamGroupMember::getRole, 3)
                        .eq(ExamGroupMember::getDelFlag, 0)
        );

        if (member == null) {
            return R.fail("您不是该考试组成员或已退出");
        }

        // 逻辑删除成员记录
        memberMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupMember>()
                        .eq(ExamGroupMember::getExamGroupId, groupId)
                        .eq(ExamGroupMember::getUserId, userId)
                        .set(ExamGroupMember::getApproveStatus, 3)
                        .set(ExamGroupMember::getUpdateTime, new Date())
                        .set(ExamGroupMember::getUpdateBy, String.valueOf(userId))
        );

        // 删除申请记录
        inviteRecordMapper.update(null,
                new LambdaUpdateWrapper<ExamGroupInviteRecord>()
                        .eq(ExamGroupInviteRecord::getExamGroupId, groupId)
                        .eq(ExamGroupInviteRecord::getInviteeId, userId)
                        .set(ExamGroupInviteRecord::getUpdateTime, new Date())
                        // 4-已退出
                        .set(ExamGroupInviteRecord::getStatus, 3)
                        .set(ExamGroupInviteRecord::getUpdateBy, String.valueOf(userId))
        );

        return R.ok(null, "退出成功");
    }

    @Override
    public TableDataInfo<ExamGroupApplicationVo> listStudentApplications(Long userId, PageQuery pageQuery) {
        IPage<ExamGroupApplicationVo> page = examGroupMapper.selectStudentApplications(
                pageQuery.build(),
                userId
        );
        return TableDataInfo.build(page);
    }

    @Override
    @Transactional
    public boolean cancelApplication(Long userId, Long applicationId) {
        ExamGroupMember member = memberMapper.selectOne(
                PlusWrappers.lambdaQuery(ExamGroupMember.class)
                        .eq(ExamGroupMember::getExamGroupId, applicationId)
                        .eqIfPresent(ExamGroupMember::getUserId, userId)
        );
        if (member == null || !member.getUserId().equals(userId)) {
            throw new ServiceException("申请记录不存在");
        }
        if (member.getApproveStatus() != 0) {
            throw new ServiceException("只有待审核的申请可以取消");
        }
        inviteRecordMapper.delete(
                PlusWrappers.lambdaUpdate(ExamGroupInviteRecord.class)
                        .eq(ExamGroupInviteRecord::getExamGroupId, applicationId)
                        .eq(ExamGroupInviteRecord::getInviteeId, userId)
        );
        return memberMapper.delete(PlusWrappers.lambdaUpdate(ExamGroupMember.class)
                .eq(ExamGroupMember::getExamGroupId, applicationId)
                .eq(ExamGroupMember::getUserId, userId)) > 0;
    }

    @Override
    public int cancelApplicationByRecordId(Long userId, Long id) {
        ExamGroupMember member = memberMapper.selectOne(
                PlusWrappers.lambdaQuery(ExamGroupMember.class)
                        .eq(ExamGroupMember::getId, id)
        );
        if (member == null || !member.getUserId().equals(userId)) {
            throw new ServiceException("申请记录不存在");
        }
        if (member.getApproveStatus() != 0) {
            throw new ServiceException("只有待审核的申请可以取消");
        }
        inviteRecordMapper.delete(
                PlusWrappers.lambdaUpdate(ExamGroupInviteRecord.class)
                        .eq(ExamGroupInviteRecord::getExamGroupId, member.getExamGroupId())
                        .eq(ExamGroupInviteRecord::getInviteeId, userId)
        );
        return memberMapper.delete(
                PlusWrappers.lambdaUpdate(ExamGroupMember.class)
                        .eq(ExamGroupMember::getId, id)
        );
    }

    private Long getUserId() {
        // 从SecurityUtils获取当前用户ID
        return SecurityUtils.getUserId();
    }
}